﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;

namespace SharpShare.Afp.Protocol {
    internal sealed class AfpCachedReply {
        public AfpCachedReply(DsiHeader header, byte[] payload) {
            this.Header = header;
            this.Payload = payload;
        }

        public DsiHeader Header { get; private set; }
        public byte[] Payload { get; private set; }
    }

    internal sealed class AfpReplyCache {
        public const int ReplayCacheSize = 32;

        private Queue<ushort> _requestIdOrder = new Queue<ushort>();
        private Dictionary<ushort, AfpCachedReply> _cachedReplyLookup = new Dictionary<ushort, AfpCachedReply>();
        private object _synclock = new object();

        public void EnqueueReply(DsiHeader header, byte[] payload) {
            lock (_synclock) {
                if (_cachedReplyLookup.ContainsKey(header.requestId)) {
                    return;
                }

                AfpCachedReply newReply = new AfpCachedReply(header, payload);

                _requestIdOrder.Enqueue(header.requestId);
                _cachedReplyLookup[header.requestId] = newReply;

                this.TrimCache();
            }
        }

        public AfpCachedReply DequeueReply(ushort requestId) {
            lock (_synclock) {
                AfpCachedReply reply;
                _cachedReplyLookup.TryGetValue(requestId, out reply);
                return reply;
            }
        }

        private void TrimCache() {
            lock (_synclock) {
                while (_requestIdOrder.Count > ReplayCacheSize) {
                    ushort oldestId = _requestIdOrder.Dequeue();

                    _cachedReplyLookup.Remove(oldestId);
                }
            }
        }
    }
}
